package com.example.chatweb.service;

import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.example.chatweb.constant.ApiConstant;
import com.example.chatweb.entity.ErnieBotTurboResponse;
import com.example.chatweb.entity.ErnieBotTurboStreamParam;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;
import org.springframework.stereotype.Service;

import java.net.Proxy;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class ErnieBotServiceImpl implements ErnieBotService {
    private static final long TIME_OUT = 30;
    private OkHttpClient okHttpClient;

    public void BaiduService() {
        this.okHttpClient(30, 30, 30, null);
    }

    private void okHttpClient(long connectTimeout, long writeTimeout, long readTimeout, Proxy proxy) {
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.connectTimeout(connectTimeout, TimeUnit.SECONDS);
        client.writeTimeout(writeTimeout, TimeUnit.SECONDS);
        client.readTimeout(readTimeout, TimeUnit.SECONDS);
        if (Objects.nonNull(proxy)) {
            client.proxy(proxy);
        }
        this.okHttpClient = client.build();
    }

    // 该方法是同步请求API，会等大模型将数据完全生成之后，返回响应结果，可能需要等待较长时间，视生成文本长度而定
    public ErnieBotTurboResponse ernieBotTurbo(ErnieBotTurboStreamParam param) {
        if (param == null) {
            log.error("参数异常：param不能为空");
            throw new RuntimeException("参数异常：param不能为空");
        }
        if (param.isStream()) {
            param.setStream(false);
        }
        String post = HttpUtil.post(ApiConstant.ERNIE_BOT_TURBO_INSTANT + ApiConstant.getToken(), JSON.toJSONString(param));
        return JSON.parseObject(post, ErnieBotTurboResponse.class);
    }

    // 该方法是通过流的方式请求API，大模型每生成一些字符，就会通过流的方式相应给客户端，
    // 我们是在 BaiduEventSourceListener.java 的 onEvent 方法中获取大模型响应的数据，其中data就是具体的数据，
    // 我们获取到数据之后，就可以通过 SSE/webscocket 的方式实时相应给前端页面展示
    public void ernieBotTurboStream(ErnieBotTurboStreamParam param, EventSourceListener eventSourceListener) {
        if (Objects.isNull(eventSourceListener)) {
            log.error("参数异常：EventSourceListener不能为空");
            throw new RuntimeException("参数异常：EventSourceListener不能为空");
        }
        if (param == null) {
            log.error("参数异常：param不能为空");
            throw new RuntimeException("参数异常：param不能为空");
        }
        if (!param.isStream()) {
            param.setStream(true);
        }
        try {
            EventSource.Factory factory = EventSources.createFactory(this.okHttpClient);
            String requestBody = JSON.toJSONString(param);
            Request request = new Request.Builder()
                    .url(ApiConstant.ERNIE_BOT_TURBO_INSTANT + ApiConstant.getToken())
                    .post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), requestBody))
                    .build();
            //创建事件
            EventSource eventSource = factory.newEventSource(request, eventSourceListener);
        } catch (Exception e) {
            log.error("请求参数解析是失败！", e);
            throw new RuntimeException("请求参数解析是失败！", e);
        }

    }
}
